package codeanticode.vision;

import processing.core.PApplet;
import com.googlecode.javacv.cpp.opencv_core.CvRect;
import com.googlecode.javacv.cpp.opencv_core.CvSeq;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import com.googlecode.javacv.cpp.opencv_core.CvMemStorage;
import com.googlecode.javacv.cpp.opencv_objdetect.CvHaarClassifierCascade;
import static com.googlecode.javacv.cpp.opencv_core.cvGetSeqElem;
import static com.googlecode.javacv.cpp.opencv_core.cvLoad;
import static com.googlecode.javacv.cpp.opencv_imgproc.cvCvtColor;
import static com.googlecode.javacv.cpp.opencv_objdetect.cvHaarDetectObjects;
import static com.googlecode.javacv.cpp.opencv_core.IPL_DEPTH_8U;
import static com.googlecode.javacv.cpp.opencv_imgproc.CV_BGR2GRAY;
import static com.googlecode.javacv.cpp.opencv_objdetect.CV_HAAR_DO_CANNY_PRUNING;

public class FaceDetector {
  protected Vision vision;
  protected IplImage grayImage;
  protected CvHaarClassifierCascade classifier;
  protected CvMemStorage storage;
  
  public FaceDetector(PApplet parent, String classFilename) {
    vision = new Vision(parent);
    
    String fullfn = parent.dataPath(classFilename);
    classifier = new CvHaarClassifierCascade(cvLoad(fullfn));
    if (classifier.isNull()) {
      System.err.println("Error loading classifier file \"" + fullfn + "\".");
      return;
    } 
    
    // Objects allocated with a create*() or clone() factory method are automatically released
    // by the garbage collector, but may still be explicitly released by calling release().
    storage = CvMemStorage.create();
  }
  
  public Rectangle[] detect(BaseGrabber grabber) {
    if (grabber.width <= 0 || grabber.height <= 0) {
      System.err.println("Error loading image.");
      return null; 
    }
    
    int w = grabber.width;
    int h = grabber.height;
    
    if (grayImage == null) {
      grayImage = IplImage.create(w, h, IPL_DEPTH_8U, 1); 
    }
    
    cvCvtColor(grabber.grabImage, grayImage, CV_BGR2GRAY);
    CvSeq faces = cvHaarDetectObjects(grayImage, classifier, storage, 1.1, 3, CV_HAAR_DO_CANNY_PRUNING);
        
    int total = faces.total();
    Rectangle[] res = new Rectangle[total];
    for (int i = 0; i < total; i++) {
      CvRect r = new CvRect(cvGetSeqElem(faces, i));        
      float xn = (float)r.x() / w; 
      float yn = (float)r.y() / h; 
      float wn = (float)r.width() / w; 
      float hn = (float)r.height() / h;
     
      res[i] = new Rectangle(xn, yn, wn, hn);   
    }
    
    return res;
  }
}
